/*
 *	Name:	emeta_exploit.c
 *
 *	Purpose:
 *	Source file containing the functions that use the enhanced metadata to calculate
 *	viewing and solar illumination angles. These functions operate on the EMETA data
 *      type defined in "emeta.h".
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "ias_logging.h"
#include "ias_odl.h"				/* ODL access routines for reading metadata  */
#include "emeta_exploit.h"			/* Definition of EMETA structure and
						   function prototypes.                      */
#include "emeta_geometry.h"			/* emeta_calc_vectors prototype              */

#define	MAX_FIELD_NAME	128			/* Maximum number of characters in an ODL
						   field name in the enhanced metadata file  */

int emeta_read(
    EMETA	*emeta,				/* Enhanced metadata structure to load       */
    const char	*emeta_filename )		/* Input file name to read                   */
{
    IAS_OBJ_DESC	*emeta_odl;		/* Enhanced metadata ODL object              */
    int		i;				/* Loop index                                */

    /* Open file */
    emeta_odl = ias_odl_read_tree( emeta_filename );
    if ( emeta_odl == NULL )
    {
        IAS_LOG_ERROR("Opening input enhanced metadata file %s.", emeta_filename);
        return(ERROR);
    }

    /* Read data */
    /* File information group */
    if ( emeta_read_file_header( emeta, emeta_odl ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading FILE_HEADER group from %s.", emeta_filename);
        ias_odl_free_tree( emeta_odl );
        return(ERROR);
    }

    /* Projection information group */
    if ( emeta_read_projection( &emeta->projection, emeta_odl ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading PROJECTION group from %s.", emeta_filename);
        ias_odl_free_tree( emeta_odl );
        return(ERROR);
    }

    /* Ephemeris data group and solar vector data group */
    if ( emeta_read_ephemeris( emeta, emeta_odl ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading EPHEMERIS group from %s.", emeta_filename);
        ias_odl_free_tree( emeta_odl );
        return(ERROR);
    }

    /* Band information */
    for ( i=0; i<emeta->num_band; i++ )
    {
        if ( emeta_read_band_meta( &emeta->band_emeta[i], emeta_odl ) != SUCCESS )
        {
            IAS_LOG_ERROR("Reading band metadata for index %d from %s.", i, emeta_filename);
            ias_odl_free_tree( emeta_odl );
            return(ERROR);
        }
    }

    /* Release the ODL structure */
    ias_odl_free_tree( emeta_odl );

    return(SUCCESS);
}

int emeta_read_file_header(
    EMETA		*emeta,			/* Enhanced metadata structure to load       */
    IAS_OBJ_DESC        *emeta_odl )		/* Enhanced metadata ODL object              */
{
    int		i;				/* Loop index                                */
    int		band_list[IAS_MAX_NBANDS];	/* Local array for loading band  numbers     */
    int		count;				/* Counter for ODL read routines             */

    /* Read data */
    /* File information fields */
//    if ( ias_odl_get_field( &emeta->wrs_path, sizeof(int), IAS_ODL_Int, emeta_odl,
//                            "FILE_HEADER", "WRS_PATH", &count ) != SUCCESS )
//    {
//        IAS_LOG_ERROR("Reading WRS_PATH from FILE_HEADER group.");
//        return(ERROR);
//    }
//    if ( ias_odl_get_field( &emeta->wrs_row, sizeof(int), IAS_ODL_Int, emeta_odl,
//                            "FILE_HEADER", "WRS_ROW", &count ) != SUCCESS )
//    {
//        IAS_LOG_ERROR("Reading WRS_ROW from FILE_HEADER group.");
//        return(ERROR);
//    }
    if ( ias_odl_get_field( &emeta->num_band, sizeof(int), IAS_ODL_Int, emeta_odl,
                            "FILE_HEADER", "NUMBER_OF_BANDS", &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading NUMBER_OF_BANDS from FILE_HEADER group.");
        return(ERROR);
    }
    if ( ias_odl_get_field( band_list, emeta->num_band*sizeof(int), IAS_ODL_Int, emeta_odl,
                            "FILE_HEADER", "BAND_LIST", &count ) != SUCCESS ||
         count != emeta->num_band )
    {
        IAS_LOG_ERROR("Reading BAND_LIST from FILE_HEADER group.");
        return(ERROR);
    }
    for ( i=0; i<emeta->num_band; i++ ) emeta->band_emeta[i].band = band_list[i];

    return(SUCCESS);
}

int emeta_read_projection(
    EMETA_SCENE_PROJ	*projection,		/* Projection structure to load              */
    IAS_OBJ_DESC        *emeta_odl )		/* Enhanced metadata ODL object              */
{
    double	coords[2];			/* Local array for loading coordinate pairs  */
    int		count;				/* Counter for ODL read routines             */
    char        field_name[MAX_FIELD_NAME];

    /* Read data */
    /* Projection information group */
    if ( ias_odl_get_field( coords, 2*sizeof(double), IAS_ODL_Double, emeta_odl,
                            "PROJECTION", "ELLIPSOID_AXES", &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading ELLIPSOID_AXES from PROJECTION group.");
        return(ERROR);
    }
    projection->wgs84_major_axis = coords[0];
    projection->wgs84_minor_axis = coords[1];
    if ( ias_odl_get_field( &projection->code, sizeof(int), IAS_ODL_Int, emeta_odl,
                            "PROJECTION", "PROJECTION_CODE", &count ) != SUCCESS )
    {
        if ( ias_odl_get_field( field_name, sizeof(field_name), IAS_ODL_String, emeta_odl,
                                "PROJECTION", "MAP_PROJECTION", &count ) != SUCCESS )
        {
            IAS_LOG_ERROR("Reading MAP_PROJECTION from PROJECTION group.");
            return(ERROR);
        }
        if(strcmp(field_name, "UTM") == 0) {
            projection->code = 1;
        } else {
            projection->code = 0;
        }
    }
    if ( ias_odl_get_field( projection->units, sizeof(projection->units), IAS_ODL_String, emeta_odl,
                            "PROJECTION", "PROJECTION_UNITS", &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading PROJECTION_UNITS from PROJECTION group.");
        return(ERROR);
    }
    if ( ias_odl_get_field( projection->datum, sizeof(projection->datum), IAS_ODL_String, emeta_odl,
                            "PROJECTION", "PROJECTION_DATUM", &count ) != SUCCESS )
    {
        if ( ias_odl_get_field( projection->datum, sizeof(projection->datum), IAS_ODL_String, emeta_odl,
                                "PROJECTION", "DATUM", &count ) != SUCCESS )
        {
            IAS_LOG_ERROR("Reading DATUM from PROJECTION group.");
            return(ERROR);
        }
    }
//    if ( ias_odl_get_field( &projection->spheroid, sizeof(int), IAS_ODL_Int, emeta_odl,
//                            "PROJECTION", "PROJECTION_SPHEROID", &count ) != SUCCESS )
//    {
//        if ( ias_odl_get_field( &projection->spheroid, sizeof(int), IAS_ODL_Int, emeta_odl,
//                                "PROJECTION", "ELLIPSOID", &count ) != SUCCESS )
//        {
//            IAS_LOG_ERROR("Reading ELLIPSOID from PROJECTION group.");
//            return(ERROR);
//        }
//    }
    if ( ias_odl_get_field( &projection->zone, sizeof(int), IAS_ODL_Int, emeta_odl,
                            "PROJECTION", "PROJECTION_ZONE", &count ) != SUCCESS )
    {
        if ( ias_odl_get_field( &projection->zone, sizeof(int), IAS_ODL_Int, emeta_odl,
                                "PROJECTION", "UTM_ZONE", &count ) != SUCCESS )
        {
            IAS_LOG_ERROR("Reading UTM_ZONE from PROJECTION group.");
            return(ERROR);
        }
    }
    if ( ias_odl_get_field( projection->projprms, IAS_PROJ_PARAM_SIZE*sizeof(double), IAS_ODL_Double, emeta_odl,
                            "PROJECTION", "PROJECTION_PARAMETERS", &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading PROJECTION_PARAMETERS from PROJECTION group.");
        return(ERROR);
    }
    if ( ias_odl_get_field( coords, 2*sizeof(double), IAS_ODL_Double, emeta_odl,
                            "PROJECTION", "UL_CORNER", &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading UL_CORNER from PROJECTION group.");
        return(ERROR);
    }
    projection->corners.upleft.x = coords[0];
    projection->corners.upleft.y = coords[1];
    if ( ias_odl_get_field( coords, 2*sizeof(double), IAS_ODL_Double, emeta_odl,
                            "PROJECTION", "UR_CORNER", &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading UR_CORNER from PROJECTION group.");
        return(ERROR);
    }
    projection->corners.upright.x = coords[0];
    projection->corners.upright.y = coords[1];
    if ( ias_odl_get_field( coords, 2*sizeof(double), IAS_ODL_Double, emeta_odl,
                            "PROJECTION", "LL_CORNER", &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading LL_CORNER from PROJECTION group.");
        return(ERROR);
    }
    projection->corners.loleft.x = coords[0];
    projection->corners.loleft.y = coords[1];
    if ( ias_odl_get_field( coords, 2*sizeof(double), IAS_ODL_Double, emeta_odl,
                            "PROJECTION", "LR_CORNER", &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading LR_CORNER from PROJECTION group.");
        return(ERROR);
    }
    projection->corners.loright.x = coords[0];
    projection->corners.loright.y = coords[1];

    return(SUCCESS);
}

int emeta_read_ephemeris(
    EMETA		*emeta,			/* Enhanced metadata structure to load       */
    IAS_OBJ_DESC        *emeta_odl )		/* Enhanced metadata ODL object              */
{
    int		i;				/* Loop index                                */
    int		year;				/* Year of acquisition                       */
    int		day;				/* Day of acquisition                        */
    double	*dbuffer;			/* Local array for loading values            */
    int		count;				/* Counter for ODL read routines             */

    /* Read data */
    /* Ephemeris data group */
    /* Ephemeris epoch time - year */
    if ( ias_odl_get_field( &year, sizeof(int), IAS_ODL_Int, emeta_odl,
                            "EPHEMERIS", "EPHEMERIS_EPOCH_YEAR", &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading EPHEMERIS_EPOCH_YEAR from EPHEMERIS group.");
        return(ERROR);
    }
    emeta->eph_epoch_time[0] = (double)year;
    /* Ephemeris epoch time - day of year */
    if ( ias_odl_get_field( &day, sizeof(int), IAS_ODL_Int, emeta_odl,
                            "EPHEMERIS", "EPHEMERIS_EPOCH_DAY", &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading EPHEMERIS_EPOCH_DAY from EPHEMERIS group.");
        return(ERROR);
    }
    emeta->eph_epoch_time[1] = (double)day;
    /* Ephemeris epoch time - second of day */
    if ( ias_odl_get_field( &emeta->eph_epoch_time[2], sizeof(double), IAS_ODL_Double, emeta_odl,
                            "EPHEMERIS", "EPHEMERIS_EPOCH_SECOND", &count ) != SUCCESS )
    {
        if ( ias_odl_get_field( &emeta->eph_epoch_time[2], sizeof(double), IAS_ODL_Double, emeta_odl,
                                "EPHEMERIS", "EPHEMERIS_EPOCH_SECONDS", &count ) != SUCCESS )
        {
            IAS_LOG_ERROR("Reading EPHEMERIS_EPOCH_SECONDS from EPHEMERIS group.");
            return(ERROR);
        }
    }
    /* Number of ephemeris points */
    if ( ias_odl_get_field( &emeta->ephem_count, sizeof(int), IAS_ODL_Int, emeta_odl,
                            "EPHEMERIS", "NUMBER_OF_POINTS", &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading NUMBER_OF_POINTS from EPHEMERIS group.");
        return(ERROR);
    }
    /* Allocate space for the input buffer */
    dbuffer = (double *)malloc( emeta->ephem_count*sizeof(double) );
    if ( dbuffer == NULL )
    {
        IAS_LOG_ERROR("Allocating ephemeris buffer.");
        return(ERROR);
    }
    /* Allocate space for the ephemeris points */
    if ( emeta_allocate_ephemeris( emeta, emeta->ephem_count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Allocating enhanced metadata ephemeris structure.");
        free( dbuffer );
        return(ERROR);
    }
    /* Ephemeris sample time offsets from epoch */
    if ( ias_odl_get_field( dbuffer, emeta->ephem_count*sizeof(double), IAS_ODL_Double, emeta_odl,
                            "EPHEMERIS", "EPHEMERIS_TIME", &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading EPHEMERIS_TIME from EPHEMERIS group.");
        return(ERROR);
    }
    for ( i=0; i<emeta->ephem_count; i++ ) emeta->ephemeris[i].eph_sample_time = dbuffer[i];
    /* Ephemeris ECEF X coordinates */
    if ( ias_odl_get_field( dbuffer, emeta->ephem_count*sizeof(double), IAS_ODL_Double, emeta_odl,
                            "EPHEMERIS", "EPHEMERIS_ECEF_X", &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading EPHEMERIS_ECEF_X from EPHEMERIS group.");
        return(ERROR);
    }
    for ( i=0; i<emeta->ephem_count; i++ ) emeta->ephemeris[i].ecef_position.x = dbuffer[i];
    /* Ephemeris ECEF Y coordinates */
    if ( ias_odl_get_field( dbuffer, emeta->ephem_count*sizeof(double), IAS_ODL_Double, emeta_odl,
                            "EPHEMERIS", "EPHEMERIS_ECEF_Y", &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading EPHEMERIS_ECEF_Y from EPHEMERIS group.");
        return(ERROR);
    }
    for ( i=0; i<emeta->ephem_count; i++ ) emeta->ephemeris[i].ecef_position.y = dbuffer[i];
    /* Ephemeris ECEF Z coordinates */
    if ( ias_odl_get_field( dbuffer, emeta->ephem_count*sizeof(double), IAS_ODL_Double, emeta_odl,
                            "EPHEMERIS", "EPHEMERIS_ECEF_Z", &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading EPHEMERIS_ECEF_Z from EPHEMERIS group.");
        return(ERROR);
    }
    for ( i=0; i<emeta->ephem_count; i++ ) emeta->ephemeris[i].ecef_position.z = dbuffer[i];
    /* Solar vector data group */
    /* Solar vector sample time offsets from epoch */
    if ( ias_odl_get_field( dbuffer, emeta->ephem_count*sizeof(double), IAS_ODL_Double, emeta_odl,
                            "SOLAR_VECTOR", "SAMPLE_TIME", &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading SAMPLE_TIME from SOLAR_VECTOR group.");
        return(ERROR);
    }
    for ( i=0; i<emeta->ephem_count; i++ ) emeta->sunvector[i].eph_sample_time = dbuffer[i];
    /* Solar vector ECEF X coordinates */
    if ( ias_odl_get_field( dbuffer, emeta->ephem_count*sizeof(double), IAS_ODL_Double, emeta_odl,
                            "SOLAR_VECTOR", "SOLAR_ECEF_X", &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading SOLAR_ECEF_X from SOLAR_VECTOR group.");
        return(ERROR);
    }
    for ( i=0; i<emeta->ephem_count; i++ ) emeta->sunvector[i].ecef_position.x = dbuffer[i];
    /* Solar vector ECEF Y coordinates */
    if ( ias_odl_get_field( dbuffer, emeta->ephem_count*sizeof(double), IAS_ODL_Double, emeta_odl,
                            "SOLAR_VECTOR", "SOLAR_ECEF_Y", &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading SOLAR_ECEF_Y from SOLAR_VECTOR group.");
        return(ERROR);
    }
    for ( i=0; i<emeta->ephem_count; i++ ) emeta->sunvector[i].ecef_position.y = dbuffer[i];
    /* Solar vector ECEF Z coordinates */
    if ( ias_odl_get_field( dbuffer, emeta->ephem_count*sizeof(double), IAS_ODL_Double, emeta_odl,
                            "SOLAR_VECTOR", "SOLAR_ECEF_Z", &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading SOLAR_ECEF_Z from SOLAR_VECTOR group.");
        return(ERROR);
    }
    for ( i=0; i<emeta->ephem_count; i++ ) emeta->sunvector[i].ecef_position.z = dbuffer[i];

    /* Free the input buffer */
    free( dbuffer );

    return(SUCCESS);
}

int emeta_read_band_meta(
    EMETA_BAND		*band_emeta,		/* Enhanced metadata band structure to load  */
    IAS_OBJ_DESC        *emeta_odl )		/* Enhanced metadata ODL object              */
{
    int		i;				/* Loop index                                */
    int		count;				/* Counter for ODL read routines             */
    int		sca_list[IAS_MAX_NSCAS];	/* Input buffer for SCA list                 */
    char	band_group[11];			/* Band group name                           */
    char	field_name[MAX_FIELD_NAME];	/* Field name                                */

    /* Read data */
    /* Band information */
    /* Construct the current band's group name */
    sprintf( band_group, "RPC_BAND%02d", band_emeta->band );
    /* Read the number of SCAs for this band */
    if ( ias_odl_get_field( &band_emeta->nsca, sizeof(int), IAS_ODL_Int, emeta_odl,
                            band_group, "NUMBER_OF_SCAS", &count ) != SUCCESS )
    {
        sprintf(field_name, "BAND%02d_NUMBER_OF_SCAS", band_emeta->band);
        if ( ias_odl_get_field( &band_emeta->nsca, sizeof(int), IAS_ODL_Int, emeta_odl,
                                band_group, field_name, &count ) != SUCCESS )
        {
            IAS_LOG_ERROR("Reading NUMBER_OF_SCAS from %s group.", band_group);
            return(ERROR);
        }
    }
    /* Read the number of L1T lines for this band */
    if ( ias_odl_get_field( &band_emeta->l1t_lines, sizeof(int), IAS_ODL_Int, emeta_odl,
                            band_group, "NUM_L1T_LINES", &count ) != SUCCESS )
    {
        sprintf(field_name, "BAND%02d_NUM_L1T_LINES", band_emeta->band);
        if ( ias_odl_get_field( &band_emeta->l1t_lines, sizeof(int), IAS_ODL_Int, emeta_odl,
                                band_group, field_name, &count ) != SUCCESS )
        {
            IAS_LOG_ERROR("Reading NUM_L1T_LINES from %s group.", band_group);
            return(ERROR);
        }
    }
    /* Read the number of L1T samples for this band */
    if ( ias_odl_get_field( &band_emeta->l1t_samps, sizeof(int), IAS_ODL_Int, emeta_odl,
                            band_group, "NUM_L1T_SAMPS", &count ) != SUCCESS )
    {
        sprintf(field_name, "BAND%02d_NUM_L1T_SAMPS", band_emeta->band);
        if ( ias_odl_get_field( &band_emeta->l1t_samps, sizeof(int), IAS_ODL_Int, emeta_odl,
                                band_group, field_name, &count ) != SUCCESS )
        {
            IAS_LOG_ERROR("Reading NUM_L1T_SAMPS from %s group.", band_group);
            return(ERROR);
        }
    }
    /* Read the number of L1R lines for this band */
    if ( ias_odl_get_field( &band_emeta->l1r_lines, sizeof(int), IAS_ODL_Int, emeta_odl,
                            band_group, "NUM_L1R_LINES", &count ) != SUCCESS )
    {
        sprintf(field_name, "BAND%02d_NUM_L1R_LINES", band_emeta->band);
        if ( ias_odl_get_field( &band_emeta->l1r_lines, sizeof(int), IAS_ODL_Int, emeta_odl,
                                band_group, field_name, &count ) != SUCCESS )
        {
            IAS_LOG_ERROR("Reading NUM_L1R_LINES from %s group.", band_group);
            return(ERROR);
        }
    }
    /* Read the number of L1R samples for this band */
    if ( ias_odl_get_field( &band_emeta->l1r_samps, sizeof(int), IAS_ODL_Int, emeta_odl,
                            band_group, "NUM_L1R_SAMPS", &count ) != SUCCESS )
    {
        sprintf(field_name, "BAND%02d_NUM_L1R_SAMPS", band_emeta->band);
        if ( ias_odl_get_field( &band_emeta->l1r_samps, sizeof(int), IAS_ODL_Int, emeta_odl,
                                band_group, field_name, &count ) != SUCCESS )
        {
            IAS_LOG_ERROR("Reading NUM_L1R_SAMPS from %s group.", band_group);
            return(ERROR);
        }
    }
    /* Read the pixel size for this band */
    if ( ias_odl_get_field( &band_emeta->pixsize, sizeof(double), IAS_ODL_Double, emeta_odl,
                            band_group, "PIXEL_SIZE", &count ) != SUCCESS )
    {
        sprintf(field_name, "BAND%02d_PIXEL_SIZE", band_emeta->band);
        if ( ias_odl_get_field( &band_emeta->pixsize, sizeof(double), IAS_ODL_Double, emeta_odl,
                                band_group, field_name, &count ) != SUCCESS )
        {
            IAS_LOG_ERROR("Reading PIXEL_SIZE from %s group.", band_group);
            return(ERROR);
        }
    }
    /* Read the image start time for this band */
    if ( ias_odl_get_field( &band_emeta->img_start_time, sizeof(double), IAS_ODL_Double, emeta_odl,
                            band_group, "START_TIME", &count ) != SUCCESS )
    {
        sprintf(field_name, "BAND%02d_START_TIME", band_emeta->band);
        if ( ias_odl_get_field( &band_emeta->img_start_time, sizeof(double), IAS_ODL_Double, emeta_odl,
                                band_group, field_name, &count ) != SUCCESS )
        {
            IAS_LOG_ERROR("Reading START_TIME from %s group.", band_group);
            return(ERROR);
        }
    }
    /* Read the line time for this band */
    if ( ias_odl_get_field( &band_emeta->line_time, sizeof(double), IAS_ODL_Double, emeta_odl,
                            band_group, "LINE_TIME", &count ) != SUCCESS )
    {
        sprintf(field_name, "BAND%02d_LINE_TIME", band_emeta->band);
        if ( ias_odl_get_field( &band_emeta->line_time, sizeof(double), IAS_ODL_Double, emeta_odl,
                                band_group, field_name, &count ) != SUCCESS )
        {
            IAS_LOG_ERROR("Reading LINE_TIME from %s group.", band_group);
            return(ERROR);
        }
    }
    /* Satellite vector RPC model */
    sprintf(field_name, "BAND%02d_MEAN_HEIGHT", band_emeta->band );
    if ( ias_odl_get_field( &band_emeta->sat.mean_hgt, sizeof(double), IAS_ODL_Double, emeta_odl,
                            band_group, field_name, &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading %s from %s group.", field_name, band_group);
        return(ERROR);
    }
    sprintf(field_name, "BAND%02d_MEAN_L1R_LINE_SAMP", band_emeta->band );
    if ( ias_odl_get_field( band_emeta->sat.mean_l1r, 2*sizeof(double), IAS_ODL_Double, emeta_odl,
                            band_group, field_name, &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading %s from %s group.", field_name, band_group);
        return(ERROR);
    }
    sprintf(field_name, "BAND%02d_MEAN_L1T_LINE_SAMP", band_emeta->band );
    if ( ias_odl_get_field( band_emeta->sat.mean_l1t, 2*sizeof(double), IAS_ODL_Double, emeta_odl,
                            band_group, field_name, &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading %s from %s group.", field_name, band_group);
        return(ERROR);
    }
    sprintf(field_name, "BAND%02d_MEAN_SAT_VECTOR", band_emeta->band );
    if ( ias_odl_get_field( band_emeta->sat.mean_vec, 3*sizeof(double), IAS_ODL_Double, emeta_odl,
                            band_group, field_name, &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading %s from %s group.", field_name, band_group);
        return(ERROR);
    }
    sprintf(field_name, "BAND%02d_SAT_X_NUM_COEF", band_emeta->band );
    if ( ias_odl_get_field( band_emeta->sat.x_num, ANG_RPC_COEF*sizeof(double), IAS_ODL_Double, emeta_odl,
                            band_group, field_name, &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading %s from %s group.", field_name, band_group);
        return(ERROR);
    }
    sprintf(field_name, "BAND%02d_SAT_X_DEN_COEF", band_emeta->band );
    if ( ias_odl_get_field( band_emeta->sat.x_den, (ANG_RPC_COEF-1)*sizeof(double), IAS_ODL_Double, emeta_odl,
                            band_group, field_name, &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading %s from %s group.", field_name, band_group);
        return(ERROR);
    }
    sprintf(field_name, "BAND%02d_SAT_Y_NUM_COEF", band_emeta->band );
    if ( ias_odl_get_field( band_emeta->sat.y_num, ANG_RPC_COEF*sizeof(double), IAS_ODL_Double, emeta_odl,
                            band_group, field_name, &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading %s from %s group.", field_name, band_group);
        return(ERROR);
    }
    sprintf(field_name, "BAND%02d_SAT_Y_DEN_COEF", band_emeta->band );
    if ( ias_odl_get_field( band_emeta->sat.y_den, (ANG_RPC_COEF-1)*sizeof(double), IAS_ODL_Double, emeta_odl,
                            band_group, field_name, &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading %s from %s group.", field_name, band_group);
        return(ERROR);
    }
    sprintf(field_name, "BAND%02d_SAT_Z_NUM_COEF", band_emeta->band );
    if ( ias_odl_get_field( band_emeta->sat.z_num, ANG_RPC_COEF*sizeof(double), IAS_ODL_Double, emeta_odl,
                            band_group, field_name, &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading %s from %s group.", field_name, band_group);
        return(ERROR);
    }
    sprintf(field_name, "BAND%02d_SAT_Z_DEN_COEF", band_emeta->band );
    if ( ias_odl_get_field( band_emeta->sat.z_den, (ANG_RPC_COEF-1)*sizeof(double), IAS_ODL_Double, emeta_odl,
                            band_group, field_name, &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading %s from %s group.", field_name, band_group);
        return(ERROR);
    }
    /* Solar vector RPC model */
    band_emeta->sun.mean_hgt = band_emeta->sat.mean_hgt;
    band_emeta->sun.mean_l1r[0] = band_emeta->sat.mean_l1r[0];
    band_emeta->sun.mean_l1r[1] = band_emeta->sat.mean_l1r[1];
    band_emeta->sat.mean_l1t[0] = band_emeta->sat.mean_l1t[0];
    band_emeta->sat.mean_l1t[1] = band_emeta->sat.mean_l1t[1];
    sprintf(field_name, "BAND%02d_MEAN_SUN_VECTOR", band_emeta->band );
    if ( ias_odl_get_field( band_emeta->sun.mean_vec, 3*sizeof(double), IAS_ODL_Double, emeta_odl,
                            band_group, field_name, &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading %s from %s group.", field_name, band_group);
        return(ERROR);
    }
    sprintf(field_name, "BAND%02d_SUN_X_NUM_COEF", band_emeta->band );
    if ( ias_odl_get_field( band_emeta->sun.x_num, ANG_RPC_COEF*sizeof(double), IAS_ODL_Double, emeta_odl,
                            band_group, field_name, &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading %s from %s group.", field_name, band_group);
        return(ERROR);
    }
    sprintf(field_name, "BAND%02d_SUN_X_DEN_COEF", band_emeta->band );
    if ( ias_odl_get_field( band_emeta->sun.x_den, (ANG_RPC_COEF-1)*sizeof(double), IAS_ODL_Double, emeta_odl,
                            band_group, field_name, &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading %s from %s group.", field_name, band_group);
        return(ERROR);
    }
    sprintf(field_name, "BAND%02d_SUN_Y_NUM_COEF", band_emeta->band );
    if ( ias_odl_get_field( band_emeta->sun.y_num, ANG_RPC_COEF*sizeof(double), IAS_ODL_Double, emeta_odl,
                            band_group, field_name, &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading %s from %s group.", field_name, band_group);
        return(ERROR);
    }
    sprintf(field_name, "BAND%02d_SUN_Y_DEN_COEF", band_emeta->band );
    if ( ias_odl_get_field( band_emeta->sun.y_den, (ANG_RPC_COEF-1)*sizeof(double), IAS_ODL_Double, emeta_odl,
                            band_group, field_name, &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading %s from %s group.", field_name, band_group);
        return(ERROR);
    }
    sprintf(field_name, "BAND%02d_SUN_Z_NUM_COEF", band_emeta->band );
    if ( ias_odl_get_field( band_emeta->sun.z_num, ANG_RPC_COEF*sizeof(double), IAS_ODL_Double, emeta_odl,
                            band_group, field_name, &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading %s from %s group.", field_name, band_group);
        return(ERROR);
    }
    sprintf(field_name, "BAND%02d_SUN_Z_DEN_COEF", band_emeta->band );
    if ( ias_odl_get_field( band_emeta->sun.z_den, (ANG_RPC_COEF-1)*sizeof(double), IAS_ODL_Double, emeta_odl,
                            band_group, field_name, &count ) != SUCCESS )
    {
        IAS_LOG_ERROR("Reading %s from %s group.", field_name, band_group);
        return(ERROR);
    }

    /* SCA numbers */
    sprintf(field_name, "BAND%02d_SCA_LIST", band_emeta->band );
    if ( ias_odl_get_field( sca_list, IAS_MAX_NSCAS*sizeof(int), IAS_ODL_Int, emeta_odl,
                            band_group, field_name, &count ) != SUCCESS ||
         count != band_emeta->nsca )
    {
            IAS_LOG_ERROR("Reading %s from %s group.", field_name, band_group);
            return(ERROR);
    }

    /* Loop through the SCAs */
    for ( i=0; i<band_emeta->nsca; i++ )
    {
        band_emeta->rpc[i].sca_num = sca_list[i];
        sprintf(field_name, "BAND%02d_SCA%02d_MEAN_HEIGHT", band_emeta->band, band_emeta->rpc[i].sca_num );
        if ( ias_odl_get_field( &band_emeta->rpc[i].mean_hgt, sizeof(double), IAS_ODL_Double, emeta_odl,
                                band_group, field_name, &count ) != SUCCESS )
        {
            IAS_LOG_ERROR("Reading %s from %s group.", field_name, band_group);
            return(ERROR);
        }
        sprintf(field_name, "BAND%02d_SCA%02d_MEAN_L1R_LINE_SAMP", band_emeta->band, band_emeta->rpc[i].sca_num );
        if ( ias_odl_get_field( band_emeta->rpc[i].mean_l1r, 2*sizeof(double), IAS_ODL_Double, emeta_odl,
                                band_group, field_name, &count ) != SUCCESS )
        {
            IAS_LOG_ERROR("Reading %s from %s group.", field_name, band_group);
            return(ERROR);
        }
        sprintf(field_name, "BAND%02d_SCA%02d_MEAN_L1T_LINE_SAMP", band_emeta->band, band_emeta->rpc[i].sca_num );
        if ( ias_odl_get_field( band_emeta->rpc[i].mean_l1t, 2*sizeof(double), IAS_ODL_Double, emeta_odl,
                                band_group, field_name, &count ) != SUCCESS )
        {
            IAS_LOG_ERROR("Reading %s from %s group.", field_name, band_group);
            return(ERROR);
        }
        sprintf(field_name, "BAND%02d_SCA%02d_LINE_NUM_COEF", band_emeta->band, band_emeta->rpc[i].sca_num );
        if ( ias_odl_get_field( band_emeta->rpc[i].line_num, NUM_RPC_COEF*sizeof(double), IAS_ODL_Double, emeta_odl,
                                band_group, field_name, &count ) != SUCCESS )
        {
            IAS_LOG_ERROR("Reading %s from %s group.", field_name, band_group);
            return(ERROR);
        }
        sprintf(field_name, "BAND%02d_SCA%02d_LINE_DEN_COEF", band_emeta->band, band_emeta->rpc[i].sca_num );
        if ( ias_odl_get_field( band_emeta->rpc[i].line_den, (NUM_RPC_COEF-1)*sizeof(double), IAS_ODL_Double, emeta_odl,
                                band_group, field_name, &count ) != SUCCESS )
        {
            IAS_LOG_ERROR("Reading %s from %s group.", field_name, band_group);
            return(ERROR);
        }
        sprintf(field_name, "BAND%02d_SCA%02d_SAMP_NUM_COEF", band_emeta->band, band_emeta->rpc[i].sca_num );
        if ( ias_odl_get_field( band_emeta->rpc[i].samp_num, NUM_RPC_COEF*sizeof(double), IAS_ODL_Double, emeta_odl,
                                band_group, field_name, &count ) != SUCCESS )
        {
            IAS_LOG_ERROR("Reading %s from %s group.", field_name, band_group);
            return(ERROR);
        }
        sprintf(field_name, "BAND%02d_SCA%02d_SAMP_DEN_COEF", band_emeta->band, band_emeta->rpc[i].sca_num );
        if ( ias_odl_get_field( band_emeta->rpc[i].samp_den, (NUM_RPC_COEF-1)*sizeof(double), IAS_ODL_Double, emeta_odl,
                                band_group, field_name, &count ) != SUCCESS )
        {
            IAS_LOG_ERROR("Reading %s from %s group.", field_name, band_group);
            return(ERROR);
        }
    }

    return(SUCCESS);
}

int emeta_angles_rpc(
    double		l1t_line,		/* Output space line coordinate              */
    double		l1t_samp,		/* Output space sample coordinate            */
    EMETA		*emeta, 		/* Enhanced metadata structure               */
    int			band, 			/* Current band number                       */
    double		*satang,		/* Satellite viewing zenith/azimuth angles   */
    double		*sunang	)		/* Solar illumination zenith/azimuth angles  */
{
    int		band_index;			/* Band index in EMETA structure             */
    int		nsca_found;			/* Number of SCAS containing the point       */
    int         isca;				/* SCA index                                 */
    double	height;				/* Model height                              */
    double	l1r_line[2];			/* Input space (L1R) line coordinate         */
    double	l1r_samp[2];			/* Input space (L1R) sample coordinate       */
    double	sat_zen;			/* Satellite zenith angle                    */
    double	sat_az;				/* Satellite azimuth angle                   */
    double	sun_zen;			/* Solar zenith angle                        */
    double	sun_az;				/* Solar azimuth angle                       */
    double	hdist;				/* Horizontal component of vector            */
    IAS_VECTOR	satvec;				/* Satellite viewing vector                  */
    IAS_VECTOR	sunvec;				/* Solar illumination vector                 */

    /* Set the band index */
    if ( (band_index = emeta_band_number_to_index( emeta, band )) < 0 )
    {
        IAS_LOG_ERROR("Band number %d not valid.", band);
        return(ERROR);
    }

    /* Set the height to use */
    height = emeta->band_emeta[band_index].sat.mean_hgt;

    /* Initialize the output vectors */
    satang[0] = satang[1] = 0.0;
    sunang[0] = sunang[1] = 0.0;

    /* See which SCA(s) the point falls inside */
    nsca_found = emeta_find_scas( l1t_line, l1t_samp, &(emeta->band_emeta[band_index]),
                                  l1r_line, l1r_samp );

    if ( nsca_found < 1 ) return(SUCCESS);	/* Outside active image, return zero vectors */
    if ( nsca_found > 2 )
    {
        IAS_LOG_ERROR("Too many SCAs found locating point in active image.");
        return(ERROR);
    }

    /* Offset the output space coordinates */
    l1t_line -= emeta->band_emeta[band_index].sat.mean_l1t[0];
    l1t_samp -= emeta->band_emeta[band_index].sat.mean_l1t[1];
    height -= emeta->band_emeta[band_index].sat.mean_hgt;

    /* Check the located SCAs */
    for ( isca=0; isca<nsca_found; isca++ )
    {
        /* Calculate the vectors using the RPCs */
        /* Satellite vector */
        l1r_line[isca] -= emeta->band_emeta[band_index].sat.mean_l1r[0];
        l1r_samp[isca] -= emeta->band_emeta[band_index].sat.mean_l1r[1];

        satvec.x =           emeta->band_emeta[band_index].sat.mean_vec[0]
                          + (emeta->band_emeta[band_index].sat.x_num[0]
                 + l1t_line*(emeta->band_emeta[band_index].sat.x_num[1]
                           + emeta->band_emeta[band_index].sat.x_num[5]*l1t_line
                           + emeta->band_emeta[band_index].sat.x_num[6]*l1t_samp)
                 + l1t_samp*(emeta->band_emeta[band_index].sat.x_num[2]
                           + emeta->band_emeta[band_index].sat.x_num[7]*l1t_samp)
                           + emeta->band_emeta[band_index].sat.x_num[3]*height
           + l1r_line[isca]*(emeta->band_emeta[band_index].sat.x_num[4]
           + l1r_line[isca]*(emeta->band_emeta[band_index].sat.x_num[8]*l1r_samp[isca]
                           + emeta->band_emeta[band_index].sat.x_num[9]*l1r_line[isca])))
                          / (1.0
                 + l1t_line*(emeta->band_emeta[band_index].sat.x_den[0]
                           + emeta->band_emeta[band_index].sat.x_den[4]*l1t_line
                           + emeta->band_emeta[band_index].sat.x_den[5]*l1t_samp)
                 + l1t_samp*(emeta->band_emeta[band_index].sat.x_den[1]
                           + emeta->band_emeta[band_index].sat.x_den[6]*l1t_samp)
                           + emeta->band_emeta[band_index].sat.x_den[2]*height
           + l1r_line[isca]*(emeta->band_emeta[band_index].sat.x_den[3]
           + l1r_line[isca]*(emeta->band_emeta[band_index].sat.x_den[7]*l1r_samp[isca]
                           + emeta->band_emeta[band_index].sat.x_den[8]*l1r_line[isca])));

        satvec.y =           emeta->band_emeta[band_index].sat.mean_vec[1]
                          + (emeta->band_emeta[band_index].sat.y_num[0]
                 + l1t_line*(emeta->band_emeta[band_index].sat.y_num[1]
                           + emeta->band_emeta[band_index].sat.y_num[5]*l1t_line
                           + emeta->band_emeta[band_index].sat.y_num[6]*l1t_samp)
                 + l1t_samp*(emeta->band_emeta[band_index].sat.y_num[2]
                           + emeta->band_emeta[band_index].sat.y_num[7]*l1t_samp)
                           + emeta->band_emeta[band_index].sat.y_num[3]*height
           + l1r_line[isca]*(emeta->band_emeta[band_index].sat.y_num[4]
           + l1r_line[isca]*(emeta->band_emeta[band_index].sat.y_num[8]*l1r_samp[isca]
                           + emeta->band_emeta[band_index].sat.y_num[9]*l1r_line[isca])))
                          / (1.0
                 + l1t_line*(emeta->band_emeta[band_index].sat.y_den[0]
                           + emeta->band_emeta[band_index].sat.y_den[4]*l1t_line
                           + emeta->band_emeta[band_index].sat.y_den[5]*l1t_samp)
                 + l1t_samp*(emeta->band_emeta[band_index].sat.y_den[1]
                           + emeta->band_emeta[band_index].sat.y_den[6]*l1t_samp)
                           + emeta->band_emeta[band_index].sat.y_den[2]*height
           + l1r_line[isca]*(emeta->band_emeta[band_index].sat.y_den[3]
           + l1r_line[isca]*(emeta->band_emeta[band_index].sat.y_den[7]*l1r_samp[isca]
                           + emeta->band_emeta[band_index].sat.y_den[8]*l1r_line[isca])));

        satvec.z =           emeta->band_emeta[band_index].sat.mean_vec[2]
                          + (emeta->band_emeta[band_index].sat.z_num[0]
                 + l1t_line*(emeta->band_emeta[band_index].sat.z_num[1]
                           + emeta->band_emeta[band_index].sat.z_num[5]*l1t_line
                           + emeta->band_emeta[band_index].sat.z_num[6]*l1t_samp)
                 + l1t_samp*(emeta->band_emeta[band_index].sat.z_num[2]
                           + emeta->band_emeta[band_index].sat.z_num[7]*l1t_samp)
                           + emeta->band_emeta[band_index].sat.z_num[3]*height
           + l1r_line[isca]*(emeta->band_emeta[band_index].sat.z_num[4]
           + l1r_line[isca]*(emeta->band_emeta[band_index].sat.z_num[8]*l1r_samp[isca]
                           + emeta->band_emeta[band_index].sat.z_num[9]*l1r_line[isca])))
                          / (1.0
                 + l1t_line*(emeta->band_emeta[band_index].sat.z_den[0]
                           + emeta->band_emeta[band_index].sat.z_den[4]*l1t_line
                           + emeta->band_emeta[band_index].sat.z_den[5]*l1t_samp)
                 + l1t_samp*(emeta->band_emeta[band_index].sat.z_den[1]
                           + emeta->band_emeta[band_index].sat.z_den[6]*l1t_samp)
                           + emeta->band_emeta[band_index].sat.z_den[2]*height
           + l1r_line[isca]*(emeta->band_emeta[band_index].sat.z_den[3]
           + l1r_line[isca]*(emeta->band_emeta[band_index].sat.z_den[7]*l1r_samp[isca]
                           + emeta->band_emeta[band_index].sat.z_den[8]*l1r_line[isca])));

        /* Solar vector */
        sunvec.x =           emeta->band_emeta[band_index].sun.mean_vec[0]
                          + (emeta->band_emeta[band_index].sun.x_num[0]
                 + l1t_line*(emeta->band_emeta[band_index].sun.x_num[1]
                           + emeta->band_emeta[band_index].sun.x_num[5]*l1t_line
                           + emeta->band_emeta[band_index].sun.x_num[6]*l1t_samp)
                 + l1t_samp*(emeta->band_emeta[band_index].sun.x_num[2]
                           + emeta->band_emeta[band_index].sun.x_num[7]*l1t_samp)
                           + emeta->band_emeta[band_index].sun.x_num[3]*height
           + l1r_line[isca]*(emeta->band_emeta[band_index].sun.x_num[4]
           + l1r_line[isca]*(emeta->band_emeta[band_index].sun.x_num[8]*l1r_samp[isca]
                           + emeta->band_emeta[band_index].sun.x_num[9]*l1r_line[isca])))
                          / (1.0
                 + l1t_line*(emeta->band_emeta[band_index].sun.x_den[0]
                           + emeta->band_emeta[band_index].sun.x_den[4]*l1t_line
                           + emeta->band_emeta[band_index].sun.x_den[5]*l1t_samp)
                 + l1t_samp*(emeta->band_emeta[band_index].sun.x_den[1]
                           + emeta->band_emeta[band_index].sun.x_den[6]*l1t_samp)
                           + emeta->band_emeta[band_index].sun.x_den[2]*height
           + l1r_line[isca]*(emeta->band_emeta[band_index].sun.x_den[3]
           + l1r_line[isca]*(emeta->band_emeta[band_index].sun.x_den[7]*l1r_samp[isca]
                           + emeta->band_emeta[band_index].sun.x_den[8]*l1r_line[isca])));

        sunvec.y =           emeta->band_emeta[band_index].sun.mean_vec[1]
                          + (emeta->band_emeta[band_index].sun.y_num[0]
                 + l1t_line*(emeta->band_emeta[band_index].sun.y_num[1]
                           + emeta->band_emeta[band_index].sun.y_num[5]*l1t_line
                           + emeta->band_emeta[band_index].sun.y_num[6]*l1t_samp)
                 + l1t_samp*(emeta->band_emeta[band_index].sun.y_num[2]
                           + emeta->band_emeta[band_index].sun.y_num[7]*l1t_samp)
                           + emeta->band_emeta[band_index].sun.y_num[3]*height
           + l1r_line[isca]*(emeta->band_emeta[band_index].sun.y_num[4]
           + l1r_line[isca]*(emeta->band_emeta[band_index].sun.y_num[8]*l1r_samp[isca]
                           + emeta->band_emeta[band_index].sun.y_num[9]*l1r_line[isca])))
                          / (1.0
                 + l1t_line*(emeta->band_emeta[band_index].sun.y_den[0]
                           + emeta->band_emeta[band_index].sun.y_den[4]*l1t_line
                           + emeta->band_emeta[band_index].sun.y_den[5]*l1t_samp)
                 + l1t_samp*(emeta->band_emeta[band_index].sun.y_den[1]
                           + emeta->band_emeta[band_index].sun.y_den[6]*l1t_samp)
                           + emeta->band_emeta[band_index].sun.y_den[2]*height
           + l1r_line[isca]*(emeta->band_emeta[band_index].sun.y_den[3]
           + l1r_line[isca]*(emeta->band_emeta[band_index].sun.y_den[7]*l1r_samp[isca]
                           + emeta->band_emeta[band_index].sun.y_den[8]*l1r_line[isca])));

        sunvec.z =           emeta->band_emeta[band_index].sun.mean_vec[2]
                          + (emeta->band_emeta[band_index].sun.z_num[0]
                 + l1t_line*(emeta->band_emeta[band_index].sun.z_num[1]
                           + emeta->band_emeta[band_index].sun.z_num[5]*l1t_line
                           + emeta->band_emeta[band_index].sun.z_num[6]*l1t_samp)
                 + l1t_samp*(emeta->band_emeta[band_index].sun.z_num[2]
                           + emeta->band_emeta[band_index].sun.z_num[7]*l1t_samp)
                           + emeta->band_emeta[band_index].sun.z_num[3]*height
           + l1r_line[isca]*(emeta->band_emeta[band_index].sun.z_num[4]
           + l1r_line[isca]*(emeta->band_emeta[band_index].sun.z_num[8]*l1r_samp[isca]
                           + emeta->band_emeta[band_index].sun.z_num[9]*l1r_line[isca])))
                          / (1.0
                 + l1t_line*(emeta->band_emeta[band_index].sun.z_den[0]
                           + emeta->band_emeta[band_index].sun.z_den[4]*l1t_line
                           + emeta->band_emeta[band_index].sun.z_den[5]*l1t_samp)
                 + l1t_samp*(emeta->band_emeta[band_index].sun.z_den[1]
                           + emeta->band_emeta[band_index].sun.z_den[6]*l1t_samp)
                           + emeta->band_emeta[band_index].sun.z_den[2]*height
           + l1r_line[isca]*(emeta->band_emeta[band_index].sun.z_den[3]
           + l1r_line[isca]*(emeta->band_emeta[band_index].sun.z_den[7]*l1r_samp[isca]
                           + emeta->band_emeta[band_index].sun.z_den[8]*l1r_line[isca])));

        /* Calculate satellite angles from vector */
        if ( satvec.z > 0.0 ) sat_zen = acos( satvec.z );
        else sat_zen = 0.0;
        satang[0] += sat_zen;
        hdist = satvec.x*satvec.x+satvec.y*satvec.y;
        if ( hdist > 0.0 ) sat_az = atan2( satvec.x, satvec.y );
        else sat_az = 0.0;
        satang[1] += sat_az;

        /* Calculate solar angles from vector */
        if ( sunvec.z > 0.0 ) sun_zen = acos( sunvec.z );
        else sun_zen = 0.0;
        sunang[0] += sun_zen;
        hdist = sunvec.x*sunvec.x+sunvec.y*sunvec.y;
        if ( hdist > 0.0 ) sun_az = atan2( sunvec.x, sunvec.y );
        else sun_az = 0.0;
        sunang[1] += sun_az;
    }

    /* Average the satellite angles */
    satang[0] /= (double)nsca_found;
    satang[1] /= (double)nsca_found;

    /* Average the sun angles */
    sunang[0] /= (double)nsca_found;
    sunang[1] /= (double)nsca_found;

    return(SUCCESS);
}

int emeta_find_scas(
    double		l1t_line,		/* Input L1T line                            */
    double		l1t_samp,		/* Input L1T sample                          */
    EMETA_BAND		*eband,			/* Enhanced metadata for current band        */
    double		*l1r_line,		/* Array of output L1R line numbers          */
    double		*l1r_samp )		/* Array of output L1R sample numbers        */
{
    int		isca;				/* SCA index                                 */
    int		nsca_found;			/* Number of SCAs containing input point     */
    int		ntry;				/* Number of SCAs tested                     */
    static int	last_sca = -1;			/* Last SCA successfully used                */
    double	l1t_l;				/* Offset value of L1T line                  */
    double	l1t_s;				/* Offset value of L1T sample                */
    double	l1r_l;				/* Local L1R line                            */
    double 	l1r_s;				/* Local L1R sample                          */

    /* Initialize the number found */
    nsca_found = 0;
    ntry = 0;

    /* Try a point in the middle of the band */
    if ( last_sca < 0 || last_sca >= eband->nsca ) isca = eband->nsca / 2;
    else isca = last_sca;

    /* Compute the RPCs for this SCA */
    while ( isca >= 0 && isca < eband->nsca )
    {
        l1t_l = l1t_line - eband->rpc[isca].mean_l1t[0];
        l1t_s = l1t_samp - eband->rpc[isca].mean_l1t[1];

        l1r_l    = (eband->rpc[isca].line_num[0] + eband->rpc[isca].line_num[1]*l1t_l + (eband->rpc[isca].line_num[2]
                 +  eband->rpc[isca].line_num[4]*l1t_l)*l1t_s)
          / (1.0 + eband->rpc[isca].line_den[0]*l1t_l + (eband->rpc[isca].line_den[1]
                 + eband->rpc[isca].line_den[3]*l1t_l)*l1t_s) + eband->rpc[isca].mean_l1r[0];
        l1r_s    = (eband->rpc[isca].samp_num[0] + eband->rpc[isca].samp_num[1]*l1t_l + (eband->rpc[isca].samp_num[2]
                 +  eband->rpc[isca].samp_num[4]*l1t_l)*l1t_s)
          / (1.0 + eband->rpc[isca].samp_den[0]*l1t_l + (eband->rpc[isca].samp_den[1]
                 + eband->rpc[isca].samp_den[3]*l1t_l)*l1t_s) + eband->rpc[isca].mean_l1r[1];

        /* See if we are in the right place */
        if ( l1r_s >= 0 && l1r_s < eband->l1r_samps )
        {
            ntry++;
            if (  l1r_l >= 0 && l1r_l < eband->l1r_lines )
            {
                l1r_line[nsca_found] = l1r_l;
                l1r_samp[nsca_found] = l1r_s + isca * eband->l1r_samps;
                nsca_found++;
            }
            last_sca = isca;
            if ( ntry > 1 ) return(nsca_found);
            if ( l1r_s < SCA_OVERLAP ) isca--;
            else if ( l1r_s > (eband->l1r_samps - SCA_OVERLAP) ) isca++;
            else return(nsca_found);
        }
        else
        {
            if ( ntry > 0 ) return(nsca_found);
            if ( isca == 0 && l1r_s < 0 )
            {
                last_sca = isca;
                return(nsca_found);
            }
            if ( isca == (eband->nsca-1) && l1r_s > eband->l1r_samps )
            {
                last_sca = isca;
                return(nsca_found);
            }
            isca = (l1r_s + isca * eband->l1r_samps) / eband->l1r_samps;
            if ( isca < 0 ) isca = 0;
            if ( isca >= eband->nsca ) isca = eband->nsca - 1;
        }
    }

    return(nsca_found);
}

int emeta_write_angfile(
    char		*root_filename,		/* Output root file name                     */
    short		*sat_zn,		/* Array of satellite zenith angles          */
    short		*sat_az,		/* Array of satellite azimuth angles         */
    short		*sun_zn,		/* Array of solar zenith angles              */
    short		*sun_az,		/* Array of solar azimuth angles             */
    EMETA_FRAME		*frame )		/* Output image framing information          */
{
    FILE		*ofp;			/* Output file pointer                       */
    char		ang_filename[PATH_MAX];	/* Output angle file name                    */
    int			count;			/* Total number of samples                   */

    /* Construct satellite view angle output file name */
    sprintf( ang_filename, "%s_V%02d.img", root_filename, frame->band );
    printf("Writing view angle band file %s.\n", ang_filename);

    /* Open output file */
    if ( (ofp = fopen( ang_filename, "wb" )) == NULL )
    {
        IAS_LOG_ERROR("Opening output view angle band file %s.", ang_filename);
        return(ERROR);
    }

    /* Calculate the total number of samples */
    count = frame->nlines * frame->nsamps;

    /* Write the Satellite Zenith Angle layer */
    if ( fwrite( sat_zn, sizeof(short), count, ofp ) != count )
    {
        IAS_LOG_ERROR("Writing satellite zenith angle layer for band %d.", frame->band);
        fclose(ofp);
        return(ERROR);
    }

    /* Write the Satellite Azimuth Angle layer */
    if ( fwrite( sat_az, sizeof(short), count, ofp ) != count )
    {
        IAS_LOG_ERROR("Writing satellite azimuth angle layer for band %d.", frame->band);
        fclose(ofp);
        return(ERROR);
    }

    /* Close the output image file */
    fclose(ofp);

    /* Create the output header file name */
    strcat( ang_filename, ".hdr" );
    printf("Writing view angle band header file %s.\n", ang_filename);

    /* Open the output header file */
    if ( (ofp = fopen( ang_filename, "w" )) == NULL )
    {
        IAS_LOG_ERROR("Opening output ENVI header file %s.", ang_filename);
        return(ERROR);
    }

    /* Write the output header file */
    fprintf( ofp, "ENVI\n" );
    fprintf( ofp, "description = {\n" );
    fprintf( ofp, "  L8 View Angle Band File for %s.}\n", root_filename );
    fprintf( ofp, "samples = %d\n", frame->nsamps );
    fprintf( ofp, "lines   = %d\n", frame->nlines );
    fprintf( ofp, "bands   = 2\n" );
    fprintf( ofp, "header offset = 0\n" );
    fprintf( ofp, "file type = ENVI Standard\n" );
    fprintf( ofp, "data type = 2\n" );
    fprintf( ofp, "interleave = bsq\n" );
    fprintf( ofp, "sensor type = Unknown\n" );
    fprintf( ofp, "byte order = 0\n" );
    if ( frame->code == 1 )
    {
        fprintf( ofp, "map info = {UTM, 1.500, 1.500, %6.3lf, %6.3lf, %6.3lf, %6.3lf, %d, North, WGS-84, units=Meters}\n",
                       frame->ul_x, frame->ul_y, frame->pixsize, frame->pixsize, frame->zone );
    }
    else if ( frame->code == 6 )
    {
        fprintf( ofp, "map info = {Polar Stereographic, 1.500, 1.500, %6.3lf, %6.3lf, %6.3lf, %6.3lf, WGS-84, units=Meters}\n",
                       frame->ul_x, frame->ul_y, frame->pixsize, frame->pixsize );
        fprintf( ofp, "projection info = {31, 6378137.000, 6356752.314, -71.000000, 0.000000, 0.0, 0.0, WGS-84, Polar Stereographic, units=Meters}\n" );
    }
    else
    {
        IAS_LOG_ERROR("Invalid map projection, not UTM or LIMA PS");
        return(ERROR);
    }
    fprintf( ofp, "wavelength units = Unknown\n" );

    /* Close the output header file */
    fclose(ofp);

    /* Construct solar angle output file name */
    sprintf( ang_filename, "%s_S%02d.img", root_filename, frame->band );
    printf("Writing sun angle band file %s.\n", ang_filename);

    /* Open output file */
    if ( (ofp = fopen( ang_filename, "wb" )) == NULL )
    {
        IAS_LOG_ERROR("Opening output sun angle band file %s.", ang_filename);
        return(ERROR);
    }

    /* Write the Solar Zenith Angle layer */
    if ( fwrite( sun_zn, sizeof(short), count, ofp ) != count )
    {
        IAS_LOG_ERROR("Writing solar zenith angle layer for band %d.", frame->band);
        fclose(ofp);
        return(ERROR);
    }

    /* Write the Solar Azimuth Angle layer */
    if ( fwrite( sun_az, sizeof(short), count, ofp ) != count )
    {
        IAS_LOG_ERROR("Writing solar azimuth angle layer for band %d.", frame->band);
        fclose(ofp);
        return(ERROR);
    }

    /* Close the output image file */
    fclose(ofp);

    /* Create the output header file name */
    strcat( ang_filename, ".hdr" );
    printf("Writing sun angle band header file %s.\n", ang_filename);

    /* Open the output header file */
    if ( (ofp = fopen( ang_filename, "w" )) == NULL )
    {
        IAS_LOG_ERROR("Opening output ENVI header file %s.", ang_filename);
        return(ERROR);
    }

    /* Write the output header file */
    fprintf( ofp, "ENVI\n" );
    fprintf( ofp, "description = {\n" );
    fprintf( ofp, "  L8 Sun Angle Band File for %s.}\n", root_filename );
    fprintf( ofp, "samples = %d\n", frame->nsamps );
    fprintf( ofp, "lines   = %d\n", frame->nlines );
    fprintf( ofp, "bands   = 2\n" );
    fprintf( ofp, "header offset = 0\n" );
    fprintf( ofp, "file type = ENVI Standard\n" );
    fprintf( ofp, "data type = 2\n" );
    fprintf( ofp, "interleave = bsq\n" );
    fprintf( ofp, "sensor type = Unknown\n" );
    fprintf( ofp, "byte order = 0\n" );
    if ( frame->code == 1 )
    {
        fprintf( ofp, "map info = {UTM, 1.500, 1.500, %6.3lf, %6.3lf, %6.3lf, %6.3lf, %d, North, WGS-84, units=Meters}\n",
                       frame->ul_x, frame->ul_y, frame->pixsize, frame->pixsize, frame->zone );
    }
    else if ( frame->code == 6 )
    {
        fprintf( ofp, "map info = {Polar Stereographic, 1.500, 1.500, %6.3lf, %6.3lf, %6.3lf, %6.3lf, WGS-84, units=Meters}\n",
                       frame->ul_x, frame->ul_y, frame->pixsize, frame->pixsize );
        fprintf( ofp, "projection info = {31, 6378137.000, 6356752.314, -71.000000, 0.000000, 0.0, 0.0, WGS-84, Polar Stereographic, units=Meters}\n" );
    }
    else
    {
        IAS_LOG_ERROR("Invalid map projection, not UTM or LIMA PS");
        return(ERROR);
    }
    fprintf( ofp, "wavelength units = Unknown\n" );

    /* Close the output header file */
    fclose(ofp);

    return(SUCCESS);
}

